import {
  type Matrix2DConfig,
  type Point2D,
  type RotateOptions,
  type ScaleOptions,
  type ShearOptions,
  type Transform2D,
  type TransformHistory,
  type TransformOptions,
  TransformType,
  type Vector2D,
} from './types';

/**
 * 二维变换矩阵类
 * 支持平移、旋转、缩放、倾斜等变换操作
 */
export class Matrix2D {
  private transform: Transform2D;
  private history: TransformHistory[] = [];
  private maxHistorySize = 50;

  /**
   * 创建单位矩阵
   */
  constructor(config?: Matrix2DConfig) {
    this.transform = config?.transform || Matrix2D.identity();
    this.addToHistory(TransformType.MATRIX, '初始化');
  }

  /**
   * 获取当前变换矩阵
   */
  getMatrix(): Transform2D {
    return { ...this.transform };
  }

  /**
   * 设置变换矩阵
   */
  setMatrix(matrix: Transform2D): this {
    this.transform = { ...matrix };
    this.addToHistory(TransformType.MATRIX, '设置矩阵');
    return this;
  }

  /**
   * 重置为单位矩阵
   */
  reset(): this {
    this.transform = Matrix2D.identity();
    this.addToHistory(TransformType.MATRIX, '重置');
    return this;
  }

  /**
   * 平移变换
   */
  translate(tx: number, ty: number, options?: TransformOptions): this {
    const translateMatrix = Matrix2D.createTranslate(tx, ty);
    this.multiply(translateMatrix, options?.origin);
    this.addToHistory(TransformType.TRANSLATE, `平移(${tx}, ${ty})`);
    return this;
  }

  /**
   * 旋转变换
   * 注意：由于y轴方向已改为向上，正角度表示顺时针旋转
   * @param angle 旋转角度（弧度）
   */
  rotate(angle: number, options?: RotateOptions): this {
    const rotateMatrix = Matrix2D.createRotate(angle);
    this.multiply(rotateMatrix, options?.origin);
    this.addToHistory(TransformType.ROTATE, `旋转(${angle.toFixed(2)}弧度)`);
    return this;
  }

  /**
   * 角度制旋转变换
   * 注意：由于y轴方向已改为向上，正角度表示顺时针旋转
   * @param degrees 旋转角度（度）
   */
  rotateDegrees(degrees: number, options?: RotateOptions): this {
    const radians = (degrees * Math.PI) / 180;
    const rotateMatrix = Matrix2D.createRotate(radians);
    this.multiply(rotateMatrix, options?.origin);
    this.addToHistory(TransformType.ROTATE, `旋转(${degrees.toFixed(2)}度)`);
    return this;
  }

  /**
   * 缩放变换
   */
  scale(sx: number, sy: number, options?: ScaleOptions): this {
    const scaleMatrix = Matrix2D.createScale(sx, sy);
    this.multiply(scaleMatrix, options?.origin);
    this.addToHistory(TransformType.SCALE, `缩放(${sx}, ${sy})`);
    return this;
  }

  /**
   * 倾斜变换
   * @param shx X轴倾斜因子
   * @param shy Y轴倾斜因子
   */
  shear(shx: number, shy: number, options?: ShearOptions): this {
    const shearMatrix = Matrix2D.createShear(shx, shy);
    this.multiply(shearMatrix, options?.origin);
    this.addToHistory(TransformType.SHEAR, `倾斜(${shx}, ${shy})`);
    return this;
  }

  /**
   * 相对于x轴反射
   */
  reflectX(options?: TransformOptions): this {
    const reflectMatrix = Matrix2D.createReflectX();
    this.multiply(reflectMatrix, options?.origin);
    this.addToHistory(TransformType.SHEAR, 'x轴反射');
    return this;
  }

  /**
   * 相对于y轴反射
   */
  reflectY(options?: TransformOptions): this {
    const reflectMatrix = Matrix2D.createReflectY();
    this.multiply(reflectMatrix, options?.origin);
    this.addToHistory(TransformType.SHEAR, 'y轴反射');
    return this;
  }

  /**
   * 相对于任意角度直线反射
   * @param angle 直线角度（弧度）
   */
  reflect(angle: number, options?: TransformOptions): this {
    const reflectMatrix = Matrix2D.createReflect(angle);
    this.multiply(reflectMatrix, options?.origin);
    this.addToHistory(TransformType.SHEAR, `反射(${angle.toFixed(2)}弧度)`);
    return this;
  }

  /**
   * 错切变换（skew）- shear的别名，直接使用倾斜因子
   * @param kx X轴错切因子
   * @param ky Y轴错切因子
   */
  skew(kx: number, ky: number, options?: TransformOptions): this {
    return this.shear(kx, ky, options);
  }

  /**
   * 相对于点的对称变换
   * @param center 对称中心点
   */
  symmetric(center: Point2D): this {
    // 先平移到原点，缩放-1，再平移回来
    this.translate(-center.x, -center.y);
    this.scale(-1, -1);
    this.translate(center.x, center.y);
    this.addToHistory(
      TransformType.SCALE,
      `相对于点(${center.x}, ${center.y})对称`,
    );
    return this;
  }

  /**
   * 矩阵乘法（组合变换）
   */
  multiply(matrix: Transform2D, origin?: Point2D): this {
    if (origin) {
      // 如果指定了变换原点，先平移到原点，应用变换，再平移回来
      this.translate(-origin.x, -origin.y);
      this.multiplyDirect(matrix);
      this.translate(origin.x, origin.y);
    } else {
      this.multiplyDirect(matrix);
    }
    return this;
  }

  /**
   * 直接矩阵乘法（不考虑变换原点）
   */
  private multiplyDirect(matrix: Transform2D): this {
    const a = this.transform.a * matrix.a + this.transform.b * matrix.c;
    const b = this.transform.a * matrix.b + this.transform.b * matrix.d;
    const c = this.transform.c * matrix.a + this.transform.d * matrix.c;
    const d = this.transform.c * matrix.b + this.transform.d * matrix.d;
    const e =
      this.transform.e * matrix.a + this.transform.f * matrix.c + matrix.e;
    const f =
      this.transform.e * matrix.b + this.transform.f * matrix.d + matrix.f;

    this.transform = { a, b, c, d, e, f };
    return this;
  }

  /**
   * 应用变换到点
   */
  transformPoint(point: Point2D): Point2D {
    const x =
      this.transform.a * point.x +
      this.transform.c * point.y +
      this.transform.e;
    const y =
      this.transform.b * point.x +
      this.transform.d * point.y +
      this.transform.f;
    return { x, y };
  }

  /**
   * 应用变换到向量（不考虑平移）
   */
  transformVector(vector: Vector2D): Vector2D {
    const x = this.transform.a * vector.x + this.transform.c * vector.y;
    const y = this.transform.b * vector.x + this.transform.d * vector.y;
    return { x, y };
  }

  /**
   * 应用变换到点集合
   */
  transformPoints(points: Point2D[]): Point2D[] {
    return points.map((point) => this.transformPoint(point));
  }

  /**
   * 应用变换到向量集合
   */
  transformVectors(vectors: Vector2D[]): Vector2D[] {
    return vectors.map((vector) => this.transformVector(vector));
  }

  /**
   * 获取变换历史
   */
  getHistory(): TransformHistory[] {
    return [...this.history];
  }

  /**
   * 撤销上一次变换
   */
  undo(): boolean {
    if (this.history.length <= 1) return false; // 不能撤销初始状态

    this.history.pop(); // 移除当前状态
    const previous = this.history[this.history.length - 1];
    this.transform = { ...previous.matrix };
    return true;
  }

  /**
   * 获取逆矩阵
   */
  inverse(): Transform2D | null {
    const det =
      this.transform.a * this.transform.d - this.transform.b * this.transform.c;

    if (Math.abs(det) < 1e-10) {
      return null; // 矩阵不可逆
    }

    const invDet = 1 / det;

    return {
      a: this.transform.d * invDet,
      b: -this.transform.b * invDet,
      c: -this.transform.c * invDet,
      d: this.transform.a * invDet,
      e:
        (this.transform.c * this.transform.f -
          this.transform.d * this.transform.e) *
        invDet,
      f:
        (this.transform.b * this.transform.e -
          this.transform.a * this.transform.f) *
        invDet,
    };
  }

  /**
   * 获取行列式
   */
  determinant(): number {
    return (
      this.transform.a * this.transform.d - this.transform.b * this.transform.c
    );
  }

  /**
   * 克隆矩阵
   */
  clone(): Matrix2D {
    return new Matrix2D({ transform: { ...this.transform } });
  }

  /**
   * 转换为CSS变换字符串
   */
  toCSSTransform(): string {
    return `matrix(${this.transform.a}, ${this.transform.b}, ${this.transform.c}, ${this.transform.d}, ${this.transform.e}, ${this.transform.f})`;
  }

  /**
   * 转换为数组形式
   */
  toArray(): number[] {
    return [
      this.transform.a,
      this.transform.b,
      this.transform.c,
      this.transform.d,
      this.transform.e,
      this.transform.f,
    ];
  }

  /**
   * 添加变换历史记录
   */
  private addToHistory(type: TransformType, description?: string): void {
    this.history.push({
      type,
      matrix: { ...this.transform },
      timestamp: Date.now(),
      description,
    });

    // 限制历史记录大小
    if (this.history.length > this.maxHistorySize) {
      this.history.shift();
    }
  }

  // 静态方法

  /**
   * 创建单位矩阵
   */
  static identity(): Transform2D {
    return { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 };
  }

  /**
   * 创建平移矩阵
   */
  static createTranslate(tx: number, ty: number): Transform2D {
    return { a: 1, b: 0, c: 0, d: 1, e: tx, f: ty };
  }

  /**
   * 创建旋转矩阵
   * 注意：由于y轴方向已改为向上，正角度表示顺时针旋转
   */
  static createRotate(angle: number): Transform2D {
    const cos = Math.cos(angle);
    const sin = Math.sin(angle);
    return { a: cos, b: sin, c: -sin, d: cos, e: 0, f: 0 };
  }

  /**
   * 创建缩放矩阵
   */
  static createScale(sx: number, sy: number): Transform2D {
    return { a: sx, b: 0, c: 0, d: sy, e: 0, f: 0 };
  }

  /**
   * 创建倾斜矩阵
   * @param shx X轴倾斜因子
   * @param shy Y轴倾斜因子
   */
  static createShear(shx: number, shy: number): Transform2D {
    return { a: 1, b: shy, c: shx, d: 1, e: 0, f: 0 };
  }

  /**
   * 创建相对于x轴的反射矩阵
   */
  static createReflectX(): Transform2D {
    return { a: 1, b: 0, c: 0, d: -1, e: 0, f: 0 };
  }

  /**
   * 创建相对于y轴的反射矩阵
   */
  static createReflectY(): Transform2D {
    return { a: -1, b: 0, c: 0, d: 1, e: 0, f: 0 };
  }

  /**
   * 创建相对于任意角度直线的反射矩阵
   * @param angle 直线角度（弧度）
   */
  static createReflect(angle: number): Transform2D {
    const cos = Math.cos(2 * angle);
    const sin = Math.sin(2 * angle);
    return { a: cos, b: sin, c: sin, d: -cos, e: 0, f: 0 };
  }

  /**
   * 从CSS变换字符串解析矩阵
   */
  static fromCSSTransform(cssTransform: string): Transform2D | null {
    const match = cssTransform.match(/matrix\(([^)]+)\)/);
    if (!match) return null;

    const values = match[1].split(',').map((v) => parseFloat(v.trim()));
    if (values.length !== 6) return null;

    return {
      a: values[0],
      b: values[1],
      c: values[2],
      d: values[3],
      e: values[4],
      f: values[5],
    };
  }

  /**
   * 从数组创建矩阵
   */
  static fromArray(arr: number[]): Transform2D | null {
    if (arr.length !== 6) return null;
    return {
      a: arr[0],
      b: arr[1],
      c: arr[2],
      d: arr[3],
      e: arr[4],
      f: arr[5],
    };
  }
}
